Unity工具类扩展

您所在的位置:网站首页 unity ui扩展 Unity工具类扩展

Unity工具类扩展

2023-07-22 16:49| 来源: 网络整理| 查看: 265

【为什么要做自动化工具】

工具类的创建是为了解决实际问题或者优化既有流程,我们来先看看一些项目里面经常遇到的问题。

下面这个工具就是可以直接创建一个功能的基础脚本类,就不用每次去复制上次的代码了。然后再帮我们把那些乱七八糟又数不胜数的按钮、文字、图片组件都自动生成在脚本里面,然后自己去关联好引用,一下就能节省好多重复的活。

效果图

####简单的 一层 qqw12.gif

####复杂点的 管理Panel 子管理Panel 孙管理

image

代码部分解析

####1 枚举类型 UIMarkType 对应指定的类型 UIType是默认自有的类型可以自己拓展

public enum UIMarkType{ DefaultUnityElement = 0, Element = 1 } public enum UIType { Transform = 0, Image = 1, RawImage = 2, Button = 3, Toggle = 4, Slider = 5, Scrollbar = 6, Dropdown = 7, InputField = 8, ScrollRect = 9, Text = 10, ToggleGroup = 11, Canvas = 12, RectTransform = 13, Animator = 14, IMark = 15,

}

#####2 接口IMark 主要用于拓展

public interface IMark { string ComponentName { get; } UIMarkType GetUIMarkType(); }

ComponentName获取要创建的类型字符 GetUIMarkType() 获取当前UIMarkType

####3 UIMark标签类 用于标记生成什么样

public class UIMark : MonoBehaviour, IMark { [Header("指定类型")] public UIMarkType MarkType = UIMarkType.DefaultUnityElement; [Header("当前选择创建属性类型")] public UIType CreateType; [Header("创建脚本类名")] public string CustomComponentName; public UIMarkType GetUIMarkType() { return MarkType; } public virtual string ComponentName { get { if (MarkType == UIMarkType.DefaultUnityElement) { if (CreateType == UIType.IMark) { return GetComponents().First(v=>v.GetType()!=this.GetType()).ComponentName; } return CreateType.ToString(); } return CustomComponentName; } } public void InitCreateType() { if (MarkType == UIMarkType.DefaultUnityElement) { var TempMark = GetComponents().Where(v => v.GetType() != this.GetType()); if (TempMark.Count()>0) CreateType = UIType.IMark; else if (null != GetComponent()) CreateType = UIType.ScrollRect; else if (null != GetComponent()) CreateType = UIType.InputField; else if (null != GetComponent()) CreateType = UIType.Text; else if (null != GetComponent()) CreateType = UIType.Button; else if (null != GetComponent()) CreateType = UIType.RawImage; else if (null != GetComponent()) CreateType = UIType.Toggle; else if (null != GetComponent()) CreateType = UIType.Slider; else if (null != GetComponent()) CreateType = UIType.Scrollbar; else if (null != GetComponent()) CreateType = UIType.Image; else if (null != GetComponent()) CreateType = UIType.ToggleGroup; else if (null != GetComponent()) CreateType = UIType.Animator; else if (null != GetComponent()) CreateType = UIType.Canvas; else if (null != GetComponent()) CreateType = UIType.RectTransform; else if (null != GetComponent()) CreateType = UIType.Transform; } } }

实现了了IMark [Header(“xxx”)]  在Inspector面板上给定义的字段的上一行加段描述 InitCreateType()是用来识别当前适合什么自有的类型 如果太多组件可能会错就要Inspector面板改了

####4 CustomEditorUIMarkEditor类 用于UIMark类的自定义Inspector面板

[CanEditMultipleObjects, CustomEditor(typeof(UIMark))] public class CustomEditorUIMarkEditor : Editor { public override void OnInspectorGUI() { EditorGUILayout.PropertyField(this.serializedObject.FindProperty("MarkType")); if (this.serializedObject.FindProperty("MarkType").enumValueIndex == 1) { EditorGUILayout.PropertyField(this.serializedObject.FindProperty("CustomComponentName")); } else { EditorGUILayout.PropertyField(this.serializedObject.FindProperty("CreateType")); } // 应用属性修改 this.serializedObject.ApplyModifiedProperties(); } }

EditorGUILayout.PropertyField 搜索自定义的类里面的属性名称 然后绘制 特性[CanEditMultipleObjects, CustomEditor(typeof(UIMark))] 每个需要重新自定义面板都需要打上这个特性标签

效果大概这样 image.png image.png

####5 AddUIMark类 右键添加按钮UIMark的

public class AddUIMark { [MenuItem("GameObject/KGUI/AddUIMark", priority = 0)] static void AddUIMarkMenu() { GameObject[] obj = Selection.gameObjects; for (int i = 0; i < obj.Length; i++) { if (!obj[i].GetComponent()) { obj[i].AddComponent().InitCreateType(); } else { obj[i].GetComponent().InitCreateType(); } } } }

MenuItem 按钮的定义 想要在Hierarchy视图右键的话 路径就要GameObject/下的 然后要选层级 默认层级是不出现在右键的

6 GeneratorData 就一些静态数据 public class GeneratorData { #region UIClass public static string UIClass = @"using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System; public class #类名# : MonoBehaviour { //替换标签 #region UIModule #成员# #endregion public void Awake() { InitFind(); } public void InitFind() { #查找# } } "; #endregion #region ElementClass public static string ElementClass = @"using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System; public class #类名# : MonoBehaviour { //这是子类 //替换标签 #region UIModule #成员# #endregion public void Awake() { InitFind(); } public void InitFind() { #查找# } } "; #endregion public static Type GetType(string name) { // Type type=null; var AssemblyCSharp = AppDomain.CurrentDomain.GetAssemblies().First(v => v.FullName.StartsWith("Assembly-CSharp,")); return AssemblyCSharp.GetType(name); } }

var AssemblyCSharp 是获取所有程序集筛选Assembly-CSharp 这个集

7 UICodeGenerator 一键生成添加脚本 public class UICodeGenerator { private static Action ff; public static GameObject gg; public static string tt="fff"; [MenuItem("GameObject/KGUI/生成脚本", priority = 0)] public static void UIScriptGenerator() { if (EditorPrefs.GetBool("ScriptGenerator")) { return; } GameObject[] selectobjs = Selection.gameObjects; foreach (GameObject go in selectobjs) { Generator(go); } } public static void ScriptGenerator(GameObject go,string UIClass, string Classname="") { //选择的物体 GameObject selectobj = go; //物体的子物体 List childList = selectobj.GetComponentsInChildren(true).ToList(); Debug.Log(childList); List ElementList = childList.Where(v => { return v.GetComponent() && v.GetComponent().MarkType == UIMarkType.Element&&v!= go.transform; }).ToList(); ElementList.ForEach(v => { v.GetComponentsInChildren(true).Where(Obj => {return Obj.GetComponent()&& Obj != v;}).ToList().ForEach(remove => { childList.Remove(remove); }); }); if (childList.Contains(go.transform)) { childList.Remove(go.transform); } // List childList = new List(_transforms); //UI需要查询的物体 var mainNode = childList.Where(v => v.GetComponent()); var nodePathList = new Dictionary(); string ClassName = Classname == "" ? go.name : Classname; //循环得到物体路径 foreach (Transform node in mainNode) { Transform tempNode = node; string nodePath = "/" + tempNode.name; while (tempNode != go.transform) { tempNode = tempNode.parent; if (tempNode != go.transform) { int index = nodePath.IndexOf('/'); nodePath = nodePath.Insert(index, "/" + tempNode.name); } } nodePath = nodePath.Substring(1); nodePathList.Add(node.name, nodePath); } //成员变量字符串 string memberstring = ""; //查询代码字符串 string loadedcontant = ""; foreach (Transform itemtran in mainNode) { //每个类的名字 字符 string typeStr = itemtran.GetComponent().ComponentName; // Debug.Log(); memberstring += "public " + typeStr + " " + itemtran.gameObject.name + " = null;\r\n\t"; //物体的路劲寻找 字符 loadedcontant += "\t\t" + itemtran.name + " = " + "gameObject.transform.Find(\"" + nodePathList[itemtran.name] + "\").GetComponent();\r\n"; } string scriptPath = Application.dataPath + "/Scripts/" + ClassName + ".cs"; string classStr = ""; gg = selectobj; tt = selectobj.name; if (!Directory.Exists(Application.dataPath + "/Scripts")) { Directory.CreateDirectory(Application.dataPath + "/Scripts"); } if (File.Exists(scriptPath)) { FileStream classfile = new FileStream(scriptPath, FileMode.Open); StreamReader read = new StreamReader(classfile); classStr = read.ReadToEnd(); read.Close(); classfile.Close(); File.Delete(scriptPath); //分割 区分手写和 生成的 string splitStr = "//替换标签"; string unchangeStr = Regex.Split(classStr, splitStr)[0]; string changeStr = Regex.Split(GeneratorData.UIClass, splitStr)[1]; StringBuilder build = new StringBuilder(); build.Append(unchangeStr); build.Append(splitStr); build.Append(changeStr); classStr = build.ToString(); } else { classStr =UIClass; } classStr = classStr.Replace("#类名#", ClassName); classStr = classStr.Replace("#查找#", loadedcontant); classStr = classStr.Replace("#成员#", memberstring); FileStream file = new FileStream(scriptPath, FileMode.CreateNew); StreamWriter fileW = new StreamWriter(file, System.Text.Encoding.UTF8); fileW.Write(classStr); fileW.Flush(); fileW.Close(); file.Close(); Debug.Log("创建脚本 " + Application.dataPath + "/Scripts/" + ClassName + ".cs 成功!"); } public static void Generator(GameObject go) { ScriptGenerator(go, GeneratorData.UIClass); go.GetComponentsInChildren(true).Where(v=>v.MarkType==UIMarkType.Element).ToList().ForEach(v=> { ScriptGenerator(v.gameObject, GeneratorData.ElementClass,v.CustomComponentName); }); EditorPrefs.SetBool("ScriptGenerator", true); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } [UnityEditor.Callbacks.DidReloadScripts] public static void AddScript() { if (!EditorPrefs.GetBool("ScriptGenerator")) { return; } EditorPrefs.SetBool("ScriptGenerator", false); AssetDatabase.Refresh(); Selection.gameObjects.ToList().ForEach(v => { if (!v.GetComponent(GeneratorData.GetType(v.name))) v.AddComponent(GeneratorData.GetType(v.name)); v.GetComponentsInChildren(true).Where(element => element.MarkType == UIMarkType.Element).ToList().ForEach(elementMark => { if (!elementMark.GetComponent(GeneratorData.GetType(elementMark.CustomComponentName))) { elementMark.gameObject.AddComponent(GeneratorData.GetType(elementMark.CustomComponentName)); UnityEngine.Object.DestroyImmediate(elementMark); } }); }); Debug.Log(tt+12344); }

}

EditorPrefs.Set/GetBool 用于面板存取数据的

UIScriptGenerator()会遍历当前选择的物体进行生成脚本 Generator() 处理生成脚本的逻辑

ScriptGenerator() 指定物体为他生成相应的脚本

先筛选出符合条件的属性的 mainNode 循环得到 物体的路径 生成路径字符 判断是否含有该文件夹没有则创建

if (!Directory.Exists(Application.dataPath + "/Scripts")) { Directory.CreateDirectory(Application.dataPath + "/Scripts"); }

通过File.Exists判断是否有该脚本 有的就只是修改脚本没有就创建

AddScript() 代码生成后 的添加操作

特性[UnityEditor.Callbacks.DidReloadScripts] 用于脚本改动的回调

好了 以上就是 整个过程 工程地址 https://github.com/LKaiGuo/KGScriptGenerator 喜欢给个星星


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3